using Digitalmes.Domain.Entities.Mes.Productions;

namespace Digitalmes.Application.Mes.Productions.WorkOrders.Commands;

/// <summary>
/// 工单排程排序命令。
/// </summary>
public sealed record SortWorkOrderCommand(long FromWoId, long ToWoId) : IRequest<IResult<bool>>;

internal sealed class SortWorkOrderCommandHandler(IRepository<ProdWorkOrder> repo) : IRequestHandler<SortWorkOrderCommand, IResult<bool>>
{
    public async Task<IResult<bool>> Handle(SortWorkOrderCommand request, CancellationToken cancellationToken)
    {
        if (request.FromWoId == request.ToWoId)
        {
            return Result.Success();
        }

        var fromWorkOrder = await repo.GetByIdAsync(request.FromWoId, cancellationToken);
        var toWorkOrder = await repo.GetByIdAsync(request.ToWoId, cancellationToken);
        if (fromWorkOrder == null || toWorkOrder == null)
        {
            return Result.Failure("未找到要排程的工单");
        }

        WoStatusEnum[] statuns = [WoStatusEnum.Scheduled, WoStatusEnum.InProgress, WoStatusEnum.OnHold];
        if (!statuns.Contains(fromWorkOrder.Status) || !statuns.Contains(toWorkOrder.Status))
        {
            return Result.Failure("工单不能进行排程调整操作");
        }

        List<ProdWorkOrder> schedules = [fromWorkOrder];

        // 向上移动
        if (fromWorkOrder.Priority > toWorkOrder.Priority)
        {
            // from 优先级更改为 to 优先级
            // 将 [to, from) 之间的所有项优先级向下移一位
            var workOrders = await repo.GetListAsync(m => m.LineId == fromWorkOrder.LineId
                && m.Priority >= toWorkOrder.Priority && m.Priority < fromWorkOrder.Priority, cancellationToken);
            fromWorkOrder.Priority = toWorkOrder.Priority;
            workOrders.ForEach(item =>
            {
                item.Priority += 1;
                schedules.Add(item);
            });
        }
        else
        {
            // 向下移动
            // from 优先级更改为 to 优先级
            // 将 (from, to] 之间的所有项优先级向上移一位
            var workOrders = await repo.GetListAsync(m => m.LineId == fromWorkOrder.LineId
                && m.Priority > fromWorkOrder.Priority && m.Priority <= toWorkOrder.Priority, cancellationToken);
            fromWorkOrder.Priority = toWorkOrder.Priority;
            workOrders.ForEach(item =>
            {
                item.Priority -= 1;
                schedules.Add(item);
            });
        }

        if (schedules.Count > 0)
        {
            var ok = await repo.UpdateAsync(schedules, m => new
            {
                m.Priority,
                m.UpdatedBy,
                m.UpdatedTime,
            }, cancellationToken);
            return Result.From(ok);
        }

        return Result.Success();
    }
}
